"""External search tools — real web-backed patent and literature lookup.

These are native Strands tools (not MCP) so they live inside the agent process.
They hit stable, scraper-friendly public APIs (NCBI E-utilities, Google Patents
deep links) rather than scraping HTML-rendered sites that block bots.
"""
from __future__ import annotations

import logging
from typing import Any
from urllib.parse import quote_plus

import requests
from strands import tool

logger = logging.getLogger(__name__)

_PUBMED_BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils"
_PATENTS_GOOGLE_SEARCH = "https://patents.google.com/?q={query}"
_PATENTS_GOOGLE_VIEW = "https://patents.google.com/patent/{id}"


@tool
def search_pubmed(query: str, max_results: int = 5) -> dict[str, Any]:
    """Search PubMed for biomedical literature (papers, patents-adjacent, reviews).

    Uses NCBI's E-utilities API — free, no API key required, reliable.

    Args:
        query: free-text search terms (e.g. "emicizumab patent 2024").
        max_results: how many records to return (1-20).

    Returns a dict with keys:
        - count: total matches on PubMed
        - results: list of {pmid, title, journal, year, authors, url, abstract_snippet}
    """
    if not query or not query.strip():
        return {"count": 0, "results": [], "error": "empty query"}
    n = max(1, min(int(max_results), 20))
    try:
        # 1. esearch → PMIDs
        esearch = requests.get(
            f"{_PUBMED_BASE}/esearch.fcgi",
            params={"db": "pubmed", "term": query, "retmode": "json", "retmax": n},
            timeout=12,
        )
        esearch.raise_for_status()
        ids = esearch.json().get("esearchresult", {}).get("idlist", [])
        if not ids:
            return {"count": 0, "results": []}

        # 2. esummary → metadata
        esum = requests.get(
            f"{_PUBMED_BASE}/esummary.fcgi",
            params={"db": "pubmed", "id": ",".join(ids), "retmode": "json"},
            timeout=12,
        )
        esum.raise_for_status()
        summaries = esum.json().get("result", {})

        results = []
        for pmid in ids:
            s = summaries.get(pmid) or {}
            if not isinstance(s, dict):
                continue
            authors = [a.get("name", "") for a in (s.get("authors") or [])][:4]
            results.append(
                {
                    "pmid": pmid,
                    "title": s.get("title", ""),
                    "journal": s.get("fulljournalname") or s.get("source", ""),
                    "year": (s.get("pubdate", "") or "").split(" ")[0][:4],
                    "authors": authors,
                    "url": f"https://pubmed.ncbi.nlm.nih.gov/{pmid}/",
                }
            )
        return {"count": int(esearch.json().get("esearchresult", {}).get("count", len(ids))), "results": results}
    except Exception as exc:
        logger.warning(f"search_pubmed failed: {exc}")
        return {"count": 0, "results": [], "error": f"{type(exc).__name__}: {exc}"}


@tool
def search_patents_web(query: str) -> dict[str, Any]:
    """Build a Google Patents search URL and expose simple patent-identifier
    deep links. Google Patents' full text is behind bot protection, so this
    tool returns reliable *links* the user can follow.

    Use this when the user asks "find the latest patent about X" or
    "link to the patent for Y" and the Eugene knowledge graph does not have
    the answer.

    Args:
        query: patent topic, assignee, drug name, etc. (e.g. "emicizumab 2024").

    Returns:
        {search_url, hint, example_direct_view_template}
    """
    q = (query or "").strip()
    if not q:
        return {"error": "empty query"}
    return {
        "search_url": _PATENTS_GOOGLE_SEARCH.format(query=quote_plus(q)),
        "hint": (
            "Google Patents full-text extraction is rate-limited; share this "
            "link with the user so they can open it themselves."
        ),
        "example_direct_view_template": _PATENTS_GOOGLE_VIEW.format(id="US-XXXXXXX-B2"),
    }
